package com.ogawa.networklib;

import android.util.Log;


import androidx.annotation.Nullable;

import com.example.reslib.Constants;
import com.example.reslib.utils.PreferenceWrapper;
import com.ogawa.networklib.networkBean.BaseResponseBean;
import com.ogawa.networklib.networkBean.DeviceStatusBean;
import com.ogawa.networklib.security.Sign;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import com.trello.rxlifecycle3.components.support.RxFragment;

import java.io.EOFException;
import java.nio.charset.Charset;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Retrofit 管理类，对 Retrofit 进行进一步的封装
 * Created by HourGlassRemember on 2018/10/25.
 */
public class RetrofitManager {

    private static final String TAG = "RetrofitManager";
    private static final int DEFAULT_TIMEOUT = 30;// 超时时间
    private static volatile RetrofitManager mInstance;
    private String sn;//按摩椅序列号
    private String imei;//手机序列号

    private ApiService apiService;// 请求接口类
    private Retrofit retrofit;

    /**
     * 私有化构造函数
     */
    private RetrofitManager() {
        // Log 信息
        final HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(
                message -> Log.e(TAG, "HttpLoggingInterceptor --- message = " + message))
                .setLevel(HttpLoggingInterceptor.Level.BODY);
        // 拦截器
        final Interceptor interceptor = chain -> {
            String appId = Constants.APP_ID;// appId
            String timeStamp = System.currentTimeMillis() + "";// 请求时间戳，精确到毫秒
            String requestId = UUID.randomUUID().toString();
            StringBuilder builder = new StringBuilder();
            Request request = chain.request();
            String method = request.method().toLowerCase();// 请求方式
            String url = request.url().toString().substring(Constants.API_SERVICE.length());// URI
            String jsonBody = "";
            RequestBody body = request.body();
            if (body != null) {
                Buffer buffer = new Buffer();
                body.writeTo(buffer);

                Charset charset = Charset.forName("UTF-8");
                MediaType contentType = body.contentType();
                if (contentType != null) {
                    charset = contentType.charset(charset);
                }
                if (isPlaintext(buffer) && charset != null) {
                    jsonBody = buffer.readString(charset);
                }
            }
            builder.append(method)
                    .append("\n")
                    .append(url)
                    .append("\n")
                    .append(appId)
                    .append("\n")
                    .append(timeStamp)
                    .append("\n")
                    .append(requestId)
                    .append("\n")
                    .append(jsonBody);
            String signature = Sign.signature(Constants.RSA_PRIVATE, builder.toString());// 签名
            PreferenceWrapper mSp = new PreferenceWrapper();
            String userToken = mSp.getStringValue(Constants.USER_TOKEN, "");
            String language = mSp.getStringValue(Constants.LANGUAGE, Constants.ZH);
            request = request.newBuilder()
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Authorization", appId)
                    .addHeader("x-timestamp", timeStamp)
                    .addHeader("x-request-id", requestId)
                    .addHeader("x-signature", signature)
                    .addHeader("x-token", userToken == null ? "" : userToken)
                    .addHeader("x-locale", language)
                    .build();
            return chain.proceed(request);
        };
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .addInterceptor(loggingInterceptor)
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .build();
        retrofit = new Retrofit.Builder()
                .baseUrl(Constants.API_SERVICE)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        apiService = retrofit.create(ApiService.class);
    }

    /**
     * 创建相应的接口代理
     *
     * @param service
     * @param <V>
     * @return
     */
    public <V> V createService(final Class<V> service) {
        return retrofit.create(service);
    }

    private boolean isPlaintext(Buffer buffer) {
        try {
            Buffer prefix = new Buffer();
            long byteCount = buffer.size() < 64 ? buffer.size() : 64;
            buffer.copyTo(prefix, 0, byteCount);
            for (int i = 0; i < 16; i++) {
                if (prefix.exhausted()) {
                    break;
                }
                int codePoint = prefix.readUtf8CodePoint();
                if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
                    return false;
                }
            }
            return true;
        } catch (EOFException e) {
            return false; // Truncated UTF-8 sequence.
        }
    }

    /**
     * 单例模式获取 Retrofit 管理类
     *
     * @return
     */
    public static RetrofitManager getInstance() {
        if (null == mInstance) {
            synchronized (RetrofitManager.class) {
                if (null == mInstance) {
                    mInstance = new RetrofitManager();
                }
            }
        }
        return mInstance;
    }

    /**
     * 请求数据的通用方法
     *
     * @param observable 请求结果观察者
     * @param observer   请求结果的回调监听
     * @param activity   绑定生命周期的Activity
     */
    public <T> void getData(Observable<BaseResponseBean<T>> observable, RxObserver<BaseResponseBean<T>> observer
            , RxAppCompatActivity activity) {
        if (observer == null) {
            observer = new RxObserver<BaseResponseBean<T>>(activity, false) {
                @Override
                public void onSuccess(BaseResponseBean<T> tBaseResponseBean) {

                }

                @Override
                public void onError(String errMsg) {

                }
            };
        }
        if (activity != null) {
            observable = observable.compose(activity.bindToLifecycle());
        }
        observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

    /**
     * 请求数据的通用方法
     *
     * @param observable 请求结果观察者
     * @param observer   请求结果的回调监听
     * @param fragment   绑定生命周期的Fragment
     */
    public <T> void getData(Observable<BaseResponseBean<T>> observable, RxObserver<BaseResponseBean<T>> observer
            , RxFragment fragment) {
        if (observer == null) {
            observer = new RxObserver<BaseResponseBean<T>>(fragment.getActivity(), false) {
                @Override
                public void onSuccess(BaseResponseBean<T> tBaseResponseBean) {

                }

                @Override
                public void onError(String errMsg) {

                }
            };
        }
        if (fragment != null) {
            observable = observable.compose(fragment.bindToLifecycle());
        }
        observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

    /**
     * 设置一下序列号
     *
     * @param sn
     */
    public void setSn(String sn) {
        this.sn = sn;
    }


    /**
     * 设置手机序列号
     *
     * @param imei
     */
    public void setImei(String imei) {
        this.imei = imei;
    }

    public ApiService getApiService() {
        return apiService;
    }
}
